using System.Collections.Generic;

namespace TfsSpam.Differ
{
    /// <summary>
    /// The FileDifferenceResult class is used to convey the result
    /// of a comparison of two files using the <see cref="FileDiffer"/>
    /// class.
    /// </summary>
    internal class FileDifferenceResult
    {
        #region -- Constructor
        /// <summary>
        /// Standard constructor for the class, initializes
        /// the public fields.
        /// </summary>
        /// <param name="differences">The list of differences between the two files.</param>
        /// <param name="truncated">Was the list of differences truncated due to there being too many differences?</param>
        /// <param name="contextLines">The number of context lines to use when checking if file differences overlap.</param>
        public FileDifferenceResult( List<FileDifference> differences, bool truncated )
        {
            Differences = GetDifferenceArray( differences );
            Truncated = truncated;
        }
        #endregion

        #region -- Public fields
        /// <summary>
        /// The array of differences found in the compared files.
        /// </summary>
        public readonly FileDifference[] Differences;

        /// <summary>
        /// Was the list of differences truncated due to there being
        /// too many differences?
        /// </summary>
        public readonly bool Truncated;
        #endregion

        #region -- Private initialization methods
        /// <summary>
        /// Copies the list of file differences to a static array.
        /// </summary>
        /// <param name="differences">The list of differences generated.</param>
        /// <param name="contextLines">The number of context lines to use when checking if file differences overlap.</param>
        /// <returns>A static array containing the differences between the files.</returns>
        private static FileDifference[] GetDifferenceArray( List<FileDifference> differences )
        {
            List<FileDifference> mergedDifferences = GetMergedDifferences( differences );
            FileDifference[] differenceArray = new FileDifference[ mergedDifferences.Count ];

            mergedDifferences.CopyTo( differenceArray );
            return differenceArray;
        }

        /// <summary>
        /// Examines the list of file differences and merges any differences that have
        /// overlapping lines.
        /// </summary>
        /// <param name="differences">The list of all differences found in the file.</param>
        /// <param name="contextLines">The number of context lines to use when checking if file differences overlap.</param>
        /// <returns>A list of <see cref="FileDifference"/> objects where any overlapping differences have been merged.</returns>
        private static List<FileDifference> GetMergedDifferences( List<FileDifference> differences )
        {
            List<FileDifference> mergedDifferences = new List<FileDifference>();

            foreach ( FileDifference difference in differences )
            {
                if ( mergedDifferences.Count == 0 )
                {
                    // This is the first difference, just add it to the list
                    // since there's nothing before it to overlap with.
                    mergedDifferences.Add( difference );
                }
                else
                {
                    FileDifference previousDifference = mergedDifferences[ mergedDifferences.Count - 1 ];

                    if ( previousDifference.Overlaps( difference ) )
                    {
                        // The current difference overlaps the previous difference, merge the two
                        // differences.
                        previousDifference.MergeDifference( difference );
                    }
                    else
                    {
                        // There's no overlap with the previous difference, add this difference
                        // as a unique difference.
                        mergedDifferences.Add( difference );
                    }
                }
            }

            return mergedDifferences;
        }
        #endregion
    }
}
